//
// Created by QU on 2024/5/6.
//

#include <iostream>
#include <fstream>
#include <sstream>
#include <functional>
#include <utility>
#include <memory>
#include <vector>
#include <map>
#include <set>
#include <cstring>

using std::cout, std::cin, std::endl, std::unitbuf;

// 1. 模板类型参数
template<typename T>
T add(const T &t1, const T &t2) {
    return decltype(t1 + t2)(t1 + t2);
}

template<typename T>
T compare(const T &t1, const T &t2) {
    if (t1 < t2) return -1;
    if (t1 > t2) return 1;
    return 0;
}

// 2. 模板类型参数
template<unsigned N, unsigned M>
int compare(const char (&p1)[N], const char (&p2)[M]) {
    return strcmp(p1, p2);
}

// 在调用这个模板的时候 compare("hi", "tom");
// 使用的是这个 int compare(const char(&p1)[3], const char(&p2)[4])

template<typename T, size_t N>
void print(const T (&a)[N]) {
    for (auto &item: a) {
        cout << item;
    }
}

// 编写 constexpr 模板，返回给定数组的大小
template<typename T, size_t N>
size_t length(const T (&a)[N]) {
    return N;
}

// 3. 类模板
template<typename T>
class Blob {
public:
    typedef T value_type;
    typedef typename std::vector<T>::size_type size_type;

    Blob();

    Blob(std::initializer_list<T> list);

    size_type size() const { return data->size(); }

    bool empty() const { return data->empty(); }

    void push_back(const T &t) { data->push_push(t); }

    void push_back(T &&t) { data->push_push(std::move(t)); }

    void pop_back();

    T &back();

    T &operator[](size_type i);

private:
    std::shared_ptr<std::vector<T>> data;

    void check(size_type i, const std::string &msg) const;
};

template<typename T>
Blob<T>::Blob(std::initializer_list<T> list): data(std::make_shared<std::vector<T>>(list)) {}

template<typename T>
void Blob<T>::pop_back() {
    check(0, "pop_back on empty Blob");
    data->pop_back();
}

template<typename T>
void Blob<T>::check(Blob::size_type i, const std::string &msg) const {
    if (i >= data->size()) {
        throw std::out_of_range(msg);
    }
}

// 3.在模板类中使用友元
//    template <typename> class BlobPtr;

//    template <typename T> class Blob{
//        friend class BlobPtr<T>;
//        friend bool operator==<T> (const Blob<T> &, const Blob<T> &);
//    };

template<typename T>
class Pal;         // 前向声明

class C {
    friend class Pal<C>;            // 用类C实例化的Pal是C的一个友元
    template<typename T> friend
    class Pal2;
};

template<typename T>
class C2 {
    friend class Pal<T>;
    friend T;       // c++11

    template<typename X>
    friend class Pal2;
    friend class Pal3;
};

// 模板类型别名
template <typename T>
using twin = std::pair<T, T>;

twin<std::string> twstring;
// 这里的twstring是std::pair<std::string, std::string> 类型, 类型需要和模板在一起.

// 如果传递的是一个string, 返回的应该是一个char&, (char的引用), 因为decltype推断是就是他.
// 我们不能使用auto & 作为返回值
template <typename Iter>
auto getReference(Iter begin, Iter end) -> decltype(*begin)
{
    return *begin;
}

// 通过remove_reference::type 脱去引用, 返回元素类型本身.
template <typename It>
auto getReference(It begin, It end) -> typename std::remove_reference<decltype(*begin)>::type
{
    return *begin;
}









int main(int argc, char const *argv[]) {
    int a = 10, b = 20;
    cout << add(a, b) << endl;

    int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    for (auto begin = std::begin(arr); begin != std::end(arr); begin++) {
        std::cout << *begin << " ";
    }


    return 0;
}
